<!--图片裁剪组件-->
<template>
    <el-dialog title="图片剪裁" custom-class="dlg-image-cropper" :visible.sync="dialogVisible" :close-on-click-modal="false"
        :close-on-press-escape="false" :append-to-body="true" width="500px">
        <div class="cropper-content">
            <div class="cropper">
                <vueCropper ref="cropper" :img="option.img" :outputSize="option.size" :outputType="option.outputType"
                    :info="true" :full="option.full" :canMove="option.canMove" :canMoveBox="option.canMoveBox"
                    :original="option.original" :autoCrop="option.autoCrop" :autoCropWidth="option.autoCropWidth"
                    :autoCropHeight="option.autoCropHeight" :fixed="option.fixed" :fixedNumber="option.fixedNumber"
                    :centerBox="option.centerBox" :infoTrue="option.infoTrue" :fixedBox="option.fixedBox"
                    @realTime="realTime" @imgLoad="imgLoad"></vueCropper>
            </div>
        </div>

        <div class="footer-btn">
            <div class="btn-group">
                <el-upload v-if="uploadURL.length > 0" :action="uploadURL" :show-file-list="false"
                    accept="image/png, image/jpeg, image/jpg" :before-upload="uploadImg">
                    <el-button size="small">+重新选择</el-button>
                </el-upload>
                <el-button size="mini" class="el-icon-plus" title="放大" style="margin-left: 15px;"
                    @click="changeScale(1)"></el-button>
                <el-button size="mini" class="el-icon-minus" title="缩小" style="margin-left: 15px;"
                    @click="changeScale(-1)"></el-button>
            </div>
            <div class="btn-group">
                <span>宽高比：</span>
                <el-input size="mini" style="width: 60px;" :readonly="option.fixed" v-model="cropW"
                    @change="changeCropW"></el-input>
                <div class="crop-split"></div>
                <el-input size="mini" style="width: 60px;" :readonly="option.fixed" v-model="cropH"
                    @change="changeCropH"></el-input>
            </div>
        </div>

        <div slot="footer" class="dialog-footer">
            <el-button @click="dialogVisible = false">取 消</el-button>
            <el-button type="primary" @click="clickSure">确认</el-button>
        </div>
    </el-dialog>
</template>

<script>
import { VueCropper } from 'vue-cropper';
import axios from 'axios';
import { getFileExt } from '../includes/common';

export default {
    name: 'ImageCropper',
    components: {
        VueCropper
    },
    data() {
        return {
            dialogVisible: false,
            crap: false,
            // 裁剪组件的基础配置option
            option: {
                img: '',
                info: true, // 裁剪框的大小信息
                outputSize: 1, // 裁剪生成图片的质量
                outputType: 'png', // 裁剪生成图片的格式
                canScale: true, // 图片是否允许滚轮缩放
                autoCrop: true, // 是否默认生成截图框
                autoCropWidth: '460', // 默认生成截图框宽度
                autoCropHeight: '300', // 默认生成截图框高度
                fixedBox: false, // 固定截图框大小 不允许改变
                fixed: false, // 是否开启截图框宽高固定比例
                fixedNumber: [1, 1], // 截图框的宽高比例
                full: true, // 是否输出原图比例的截图
                canMoveBox: true, // 截图框能否拖动
                original: false, // 上传图片按照原始比例渲染
                centerBox: true, // 截图框是否被限制在图片里面
                infoTrue: true // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
            },
            _option: null,
            callbackFunc: null,
            uploadURL: '',
            cropW: 0,
            cropH: 0,
            showOriginSize: false // 是否默认显示原图大小
        };
    },
    created: function () {
        this._option = JSON.parse(JSON.stringify(this.option));
    },
    methods: {
        /*
        注意：gif不支持裁剪, imageCropper会直接上传

        参数：
        config：
            {
                img: <File, 图片file, 支持裁剪的图片格式有：jpg|jpeg|png|bmp>,
                uploadURL: <string, 图片上传地址>,
                option: <object, vue-cropper的配置参数>
            }
        注意：如果要让图片截图框默认为图片大小，只设置fixed: false，不设置fixedNumber、autoCropWidth、autoCropHeight

        callback: 裁剪完成后的回调函数，回调函数返回值：
            {
                id: <long, 图片id>,
                blob: <Blob, 裁剪后的图片>
                error: 0,
                message: "",
            }
        */
        async show(config, callback) {
            this.uploadURL = config.uploadURL;

            this.showOriginSize = false;

            if (config.option) {
                this.option = JSON.parse(JSON.stringify(this._option));
                Object.assign(this.option, config.option);

                if (config.option.fixed === false) {
                    this.showOriginSize = true;

                    let img = new Image();
                    img.src = config.img;
                    img.onload = () => {
                        this.option.autoCropWidth = img.width;
                        this.option.autoCropHeight = img.height;
                    };
                }
            }

            this.callbackFunc = callback;

            let ext = getFileExt(config.img.name);
            ext = ext.toLocaleLowerCase();
            if (ext === 'gif') {
                // gif不支持裁剪
                let data = await this.uploadData(config.img);
                data['blob'] = window.URL.createObjectURL(config.img);
                callback(data);
                return;
            }

            let reader = new FileReader();
            reader.onload = (e) => {
                this.option.img = window.URL.createObjectURL(new Blob([e.target.result]));
                this.dialogVisible = true;
            };
            // 转化为blob
            reader.readAsArrayBuffer(config.img);
        },
        clickSure() {
            try {
                this.$refs.cropper.getCropBlob(async (data) => {
                    let res = await this.uploadData(data);
                    res['blob'] = window.URL.createObjectURL(data);
                    if (this.callbackFunc) {
                        this.dialogVisible = false;
                        this.callbackFunc(res);
                    }
                });

            } catch (err) {
                this.$message({
                    showClose: true,
                    message: '保存图片失败，' + err.message,
                    type: 'error'
                });
            }
        },
        // 放大/缩小
        changeScale(num) {
            console.log('changeScale');
            num = num || 1;
            this.$refs.cropper.changeScale(num);
        },
        // 上传图片
        uploadData(blob) {
            return new Promise((resolve, reject) => {
                let formData = new FormData();
                formData.append('file', blob, 'image.png');
                axios.post(this.uploadURL, formData, {
                    contentType: false,
                    processData: false,
                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
                }).then(({ data }) => {
                    resolve(data);
                }).catch((err) => {
                    reject(err);
                });
            });
        },
        // 实时预览函数
        realTime(data) {
            if (!this.option.fixed) {
                this.cropW = this.$refs.cropper.cropInfo.width;
                this.cropH = this.$refs.cropper.cropInfo.height;
            }
        },
        changeCropW(value) {
            let scale = this.$refs.cropper.scale;
            this.$refs.cropper.changeCrop(parseInt(value) * scale, parseInt(this.cropH) * scale);
            // this.option.autoCropWidth = value;
            // this.option.autoCropHeight = this.cropH;
        },
        changeCropH(value) {
            let scale = this.$refs.cropper.scale;
            this.$refs.cropper.changeCrop(parseInt(this.cropW) * scale, parseInt(value) * scale);
            // this.option.autoCropWidth = this.cropW;
            // this.option.autoCropHeight = value;
        },
        // 选择本地图片
        uploadImg(file) {
            let _this = this;
            // 上传图片
            if (!/\.(jpg|jpeg|png|bmp)$/i.test(file.name)) {
                this.$message({
                    showClose: true,
                    message: '图片类型必须是jpeg,jpg,png,bmp中的一种',
                    type: 'warning'
                });
                return false;
            }
            let reader = new FileReader();
            reader.onload = (e) => {
                let data;
                if (typeof e.target.result === 'object') {
                    // 把Array Buffer转化为blob 如果是base64不需要
                    data = window.URL.createObjectURL(new Blob([e.target.result]));
                } else {
                    data = e.target.result;
                }
                _this.option.img = data;
            };
            // 转化为base64
            // reader.readAsDataURL(file)
            // 转化为blob
            reader.readAsArrayBuffer(file);

            return false;
        },
        imgLoad(msg) {
            console.log('imgLoad');
            console.log(msg);

            if (!this.showOriginSize) {
                let scale = this.$refs.cropper.scale;
                if (this.option.autoCropWidth > 0) {
                    this.$refs.cropper.changeCrop(parseInt(this.option.autoCropWidth) * scale,
                        parseInt(this.option.autoCropHeight) * scale);
                }
            }
        }
    }
};
</script>

<style lang="scss">
.dlg-image-cropper {
    .cropper-content {
        display: flex;
        justify-content: flex-end;
        height: 310px;

        .cropper {
            width: 500px;
            height: 300px;
        }
    }

    .footer-btn {
        margin-top: 20px;
        display: flex;
        justify-content: space-between;

        .btn-group {
            display: flex;
            align-items: center;
            flex-grow: 0;
            flex-shrink: 0;
        }

        .crop-split {
            width: 30px;
            height: 30px;
            background: url("../assets/images/crop/split.png") no-repeat center;
        }
    }
}
</style>